﻿/**
 * ...
 * @author Krzysztof Rozalski
 */

package hapi.util.profiler.flash;
#if flash9
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.system.System;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
#elseif flash8
import flash.MovieClip;
import flash.TextField;
import flash.TextFormat;
import hapi.flash.util.DrawingFactory;
#else
import nme.display.Sprite;
import nme.events.Event;
import nme.events.MouseEvent;
import nme.system.System;
import nme.text.TextField;
import nme.text.TextFormat;
import nme.text.TextFormatAlign;
#end

import flash.geom.Point;
import hapi.math.MathUtil;

enum ViewType {
	FULL;
	SMALL;
}
#if  (flash9 || cpp || neko)
typedef Canvas = Sprite;
#elseif flash
typedef Canvas = flash.MovieClip;
#end

import hapi.util.profiler.flash.FrameRateMeter;

class FrameRateDisplay #if (flash9 || cpp || neko) extends Sprite #end {
	
	var currentView:ViewType;
	var title:TextField;
	var current:TextField;
	var average:TextField;
	var memory:TextField;
	var lastEvent:FrameRateEvent;
	var canvas:Canvas;
	var frameRateListener:hapi.event.Listener<FrameRateEvent>;
	var frameRateMeter:FrameRateMeter;
	
	public function new(?autoAlignToRightCorner=true) {
		#if (flash9 || cpp || neko)
		super();
		currentView = ViewType.SMALL;
		canvas = this;
		init();
		redraw();
		if (autoAlignToRightCorner) {
			this.addEventListener( Event.ADDED_TO_STAGE, autoAlign );
		}
		#end
		currentView = ViewType.SMALL;
	}
	
	public static function placeOnStage(?fullSize=true):FrameRateDisplay {
		var frameRateDisplay = new FrameRateDisplay();
		if(fullSize) frameRateDisplay.fullSize();
		#if (flash9 || cpp || neko)
			flash.Lib.current.addChild(frameRateDisplay);
		#end
		return frameRateDisplay;
	}
	
	public function renderOn(root:Canvas) {
		#if (flash9 || cpp || neko)
		root.addChild(this);
		#elseif flash
		canvas = root.createEmptyMovieClip("__hapi_fps__", 999999);
		init();
		redraw();
		autoAlign();
		#end
	}
	
	public function fullSize():Void {
		if (isMinimized()) {
			currentView = ViewType.FULL;
			redraw();
		}
	}
	
	public function smallSize():Void {
		if (!isMinimized()) {
			currentView = ViewType.SMALL;
			redraw();
		}
	}
	
	function init() {
		var textHeight = getTextHeight();
		title = createTextField(0xffff00, 0);
		current = createTextField(0x65FF00, textHeight);
		average = createTextField(0x65FF00, textHeight*2);
		memory = createTextField(0xFF0000, textHeight*3);
		lastEvent = { currentRate:0, averageRate:.0 };
		title.text = "FPS";
		initEvents();
	}
	
	function getTextHeight():Float {
		#if (android || as3)
		return 20;
		#else
		return 15;
		#end
	}
	
	function initEvents() {
		changeMeter(FrameRateMeter.getStageMeter());
		#if (flash9 || cpp || neko)
		this.addEventListener( MouseEvent.CLICK, handleClick );
		#elseif flash
		canvas.onRelease = handleClick;
		#end
	}
	
	function redraw() {
		refreshVisibility();
		drawBackground();
		resizeTextFields();
		alignTextFields();
		refreshText();
	}
	
	function createTextField(color, y) {
		var align = #if  (flash9 || cpp || neko) TextFormatAlign.CENTER #else "center" #end;
		#if (android || as3)
		var f = new TextFormat("Arial", 15, color, false, false, false, null, null, align);
		#else
		var f = new TextFormat("_sans", 10, color, false, false, false, null, null, align);
		#end
		#if (flash9 || cpp || neko)
		var tf = new TextField();
		tf.defaultTextFormat = f;
		tf.selectable = false;
		this.addChild(tf);
		tf.height = getTextHeight();
		tf.y = y;
		#elseif flash
		var depth = canvas.getNextHighestDepth();
		var tf = canvas.createTextField("tf_"+depth, depth, 0, 0, 1, 15);
		tf.setNewTextFormat(f);
		tf.selectable = false;
		tf._height = getTextHeight();
		tf._y = y;
		#end
		return tf;
	}
	
	public function changeMeter(meter:FrameRateMeter):Void {
		if (frameRateListener != null) this.frameRateMeter.onFrameRateUpdate.stopNotifying(frameRateListener);
		this.frameRateMeter = meter;
		frameRateListener = meter.onFrameRateUpdate.call(updateFrameRate);
	}
	
	function updateFrameRate(e:FrameRateEvent) {
		lastEvent = e;
		refreshText();
	}
	
	function drawBackground() {
		#if (flash9 || cpp || neko)
		var alpha = 0.7;
		var g = canvas.graphics;
		#elseif flash
		var alpha = 70;
		var g = canvas;
		#end
		g.clear();
		g.beginFill(0x2C2C2C, alpha);
		var w, h:Float;
		var s = getSize();
		#if (flash9 || cpp || neko)
		g.drawRect( -s.width, 0, s.width, s.height);
		#elseif flash
		var df = hapi.flash.util.DrawingFactory.getInstance(g);
		df.drawRect( -s.width, 0, s.width, s.height);
		#end
		g.endFill();
	}
	
	function refreshVisibility() {
		var visible = !isMinimized();
		#if (flash9 || cpp || neko)
		memory.visible = average.visible = title.visible = visible;
		#elseif flash
		memory._visible = average._visible = title._visible = visible;
		#end
	}
	
	function refreshText() {
		var currentRateText = isMinimized() ? Std.string(lastEvent.currentRate) : lastEvent.currentRate+" NOW";
		current.text = currentRateText;
		average.text = lastEvent.averageRate + " AVG";
		#if  (flash9 || cpp || neko)
		memory.text = MathUtil.roundTo(System.totalMemory / (1024 * 1024), 2) + " MB";
		#elseif flash
		memory.text = "?? MB";
		#end
	}
	
	function alignTextFields() {
		var x = -getSize().width;
		var y = isMinimized() ? 0 : 15;
		#if  (flash9 || cpp || neko)
		memory.x = title.x = average.x = current.x = x;
		current.y = y;
		#elseif flash
		memory._x = title._x = average._x = current._x = x;
		current._y = y;
		#end
	}
	
	function resizeTextFields() {
		var w = getSize().width;
		#if  (flash9 || cpp || neko)
		memory.width = title.width = average.width = current.width = w;
		#elseif flash
		memory._width = title._width = average._width = current._width = w;
		#end
	}
	
	function handleClick(#if (flash9 || cpp || neko) e #end) {
		if ( isMinimized() ) {
			currentView = ViewType.FULL;
		}else {
			currentView = ViewType.SMALL;
		}
		redraw();
	}
	
	function isMinimized() {
		return currentView == ViewType.SMALL;
	}
	
	function getSize() {
		if (isMinimized()) {
			#if (android || as3)
			return { width:30, height:getTextHeight() + 10 };
			#else
			return { width:30, height:getTextHeight() };
			#end
		}else {
			return { width:70, height:getTextHeight() * 4 };
		}
	}
	
	function autoAlign(#if  (flash9 || cpp || neko) e #end) {
		#if  (flash9 || cpp || neko)
		this.removeEventListener( Event.ADDED_TO_STAGE, autoAlign );
		var p = new Point(this.stage.stageWidth-2, 2);
		this.parent.globalToLocal(p);
		this.x = p.x;
		this.y = p.y;
		#elseif flash
		var p = new Point(flash.Lib.current._width-72, 2);
		canvas._parent.globalToLocal(p);
		canvas._x = p.x;
		canvas._y = p.y;
		#end
	}
}